#include <linux/module.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/ip.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>

/*
   网络设备驱动：
   1. 网络设备驱动框架
   2. 网络设备驱动框架的初始化
   3. 网络设备驱动框架的注册
   4. 网络设备驱动框架的卸载
   5. 网络设备驱动框架的发送
   6. 网络设备驱动框架的接收
   7. 网络设备驱动框架的调试
*/

/*
  linux设备驱动对网络定义了4层的层次结构：
  1. 网络协议接口层：dev_queue_xmit()发送接口和netif_rx()接收接口。
  2. 网络设备接口层：net_device结构体，定义了网络设备的基本属性和操作函数。
  3. 设备驱动功能层：hard_start_xmit()发送函数和hard_header()接收函数。
  4. 网络设备媒介层： 网络设备硬件，如网卡等。
  通过这四层，连接设备的硬件和应用程序之间的数据交互。
*/

// 简单的示例 ： 

#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>

static struct net_device *my_netdev;

static int my_netdev_open(struct net_device *dev)
{
    netif_start_queue(dev);
    return 0;
}

static int my_netdev_stop(struct net_device *dev)
{
    netif_stop_queue(dev);
    return 0;
}

static netdev_tx_t my_netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
    // 实现发送逻辑
    return NETDEV_TX_OK;
}

static struct net_device_ops my_netdev_ops = {
    .ndo_open = my_netdev_open,
    .ndo_stop = my_netdev_stop,
    .ndo_start_xmit = my_netdev_start_xmit,
    // 其他操作...
};

static int __init my_netdev_init(void)
{
    my_netdev = alloc_etherdev(0);
    if (!my_netdev)
        return -ENOMEM;

    my_netdev->netdev_ops = &my_netdev_ops;
    // 初始化其他设备属性...

    if (register_netdev(my_netdev)) {
        free_netdev(my_netdev);
        return -ENODEV;
    }

    return 0;
}

static void __exit my_netdev_exit(void)
{
    unregister_netdev(my_netdev);
    free_netdev(my_netdev);
}

module_init(my_netdev_init);
module_exit(my_netdev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Name");
MODULE_DESCRIPTION("A simple network device driver");





/*
  网络模型的四层详细接口：
  1. 网络协议接口层：
   - dev_queue_xmit(struct sk_buff *skb)：发送接口，将数据包发送到网络协议栈。 
   - netif_rx(struct sk_buff *skb)：接收接口，将数据包从网络协议栈传递到上层协议。
        sk_buff:   套接字缓存区 *******
        sk_buff是Linux内核中用于表示网络数据包的结构体，它包含了数据包的头部、数据、长度、协议等信息。
        sk_buff结构体是网络设备驱动程序的核心，它提供了对数据包的封装、解封装、发送和接收等功能。
        分配：
        alloc_skb(unsigned int len, gfp_t gfp_mask) 函数用于分配sk_buff结构体，
        dev_kfree_skb(unsigned int len) 函数用于释放sk_buff结构体。
        释放：
        dev_kfree_skb(struct sk_buff *skb) 函数用于释放sk_buff结构体。
        变更：
        skb_put(struct sk_buff *skb, unsigned int len) 函数用于在sk_buff结构体尾部添加数据。
        skb_push(struct sk_buff *skb, unsigned int len) 函数用于在sk_buff结构体头部添加数据。
        skb_pull(struct sk_buff *skb, unsigned int len) 函数用于从sk_buff结构体中删除数据。
  2. 网络设备接口层：
   - net_device结构体：定义了网络设备的基本属性和操作函数，是网络设备驱动的最核心的结构体。
   - net_device_ops结构体：定义了网络设备的操作函数。
  3. 设备驱动功能层：
   - hard_start_xmit(struct sk_buff *skb, struct net_device *dev)：发送函数，将网络协议接口层的数据包发送到网络设备。
   - hard_header(struct sk_buff *skb)：接收函数，将数据包从网络设备传递到上层协议,接收的数据传到网络协议接口层。
  4. 网络设备媒介层： 网络设备硬件，如网卡等。



    网络设备的注册和注销：
    register_netdev(struct net_device *dev)：注册网络设备。
    unregister_netdev(struct net_device *dev)：注销网络设备。
    生成 net_device 结构体：
    alloc_etherdev(int sizeof_priv)：分配一个以太网设备结构体，并初始化其成员。
    free_netdev(struct net_device *dev)：释放一个网络设备结构体。
    网络设备主要有初始化、注册和注销、打开和释放、发送和接收等操作。
*/


// DM9000 网卡设备驱动框架
// DM9000 网卡可以和CPU直连，内部自带缓存4K的双字节SRAM 



#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/delay.h>

// 定义硬件寄存器地址
#define DM9000_BASE_ADDR 0x97802800

// 初始化函数
static int dm9000_init(struct net_device *dev) {
    // 初始化硬件
    dm9000_init_dm9000(dev);
    /* 申请中断处理 */
    if(request_irq(dev->irq, dm9000_interrupt, IRQF_SHARED, dev->name, dev))
    {
        return -EIO;
    }

    mii_check_media(&dev->mii, netif_msg_link(db), 1);
    netif_start_queue(dev);
    return 0;
}

// 发送函数
static int dm9000_send_packet(struct sk_buff *skb, struct net_device *dev) {
    // 发送数据包
    // ...
    return 0;
}

// 接收函数
static void dm9000_rx(struct net_device *dev) {
    // 接收数据包
    // ...
}

// 中断处理函数
static irqreturn_t dm9000_interrupt(int irq, void *dev_id) {
    struct net_device *dev = dev_id;
    // 处理中断
    // ...
    return IRQ_HANDLED;
}

// 驱动结构体
static struct net_device_ops dm9000_ops = {
    .ndo_init = dm9000_init,
    .ndo_start_xmit = dm9000_send_packet,
    // ...
};

// 模块加载函数
static int __init dm9000_driver_init(void) {
    //1)使用alloc_netdev()来分配一个net_device结构体
    struct net_device *dev;
    dev = alloc_netdev(0, "dm9000", NETDEV_BOOT, ether_setup);
    if (!dev)
        return -ENOMEM;
    //2)设置网卡硬件相关的寄存器
    dev->base_addr = DM9000_BASE_ADDR;
    dev->irq = 0;

    //3)设置net_device结构体的成员
    dev->netdev_ops = &dm9000_ops;
    //4)使用register_netdev()来注册net_device结构体

    // 注册网络设备
    register_netdev(dev);
    return 0;
}

// 模块卸载函数
static void __exit dm9000_driver_exit(void) {
    struct net_device *dev = dev_get_by_name(&init_net, "dm9000");
    if (dev) {
        unregister_netdev(dev);
        free_netdev(dev);
    }
}

module_init(dm9000_driver_init);
module_exit(dm9000_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("SJZ");
MODULE_DESCRIPTION("DM9000 Ethernet Driver");


/*
    虚拟网卡驱动编写，虚拟网卡不需要硬件相关的操作，所以不需要中断处理函数，只需要实现初始化、发送和接收函数即可。

*/


/*
   sk_buff 结构  

   struct sk_buff {
        struct sk_buff *next;  // 指向下一个sk_buff结构体
        struct sk_buff *prev;  // 指向前一个sk_buff结构体
        struct sk_buff *list;  // 指向sk_buff结构体链表
        unsigned int len;      // sk_buff结构体中数据的长度
        unsigned int data_len; // sk_buff结构体中数据的实际长度
        unsigned char *head;   // 指向sk_buff结构体中的头部
        unsigned char *data;   // 指向sk_buff结构体中的数据
        unsigned char *tail;   // 指向sk_buff结构体中的尾部
        unsigned char *end;    // 指向sk_buff结构体中的尾部
   }
    sk_buff 结构体中的数据布局如下：
        ___________________________________________________
        | 存放协议头的头部空间  |   数据包   |    尾部空间   | 
        ————————————————————————————————————————————————————  
*/

/*

网卡发送数据包过程：
    1、把数据包发出去之前,需要使用**netif_stop_queue()**来停止上层传下来的数据包；
    2.1、设置寄存器，通过网络设备硬件来发送数据
    2.2、当数据包发出去后, 再调用dev_kfree_skb()函数来释放sk_buff,该函数原型如下:void dev_kfree_skb(struct sk_buff *skb);
    3、当数据包发出成功,就会进入TX接收中断函数，然后更新统计信息，调用**netif_wake_queue()**来唤醒，启动上层继续发包下来；
    4、若数据包发出去超时，一直进不到TX中断函数,就会调用net_device结构体的*tx_timeout超时成员函数，在该函数中更新统计信息，并调用netif_wake_queue()来唤醒。
网卡接收数据包过程：
    1、使用dev_alloc_skb()来构造一个新的sk_buff；
    2、使用skb_reserve(rx_skb, 2) 将sk_buff缓冲区里的数据包先向后位移2字节，腾出sk_buff缓冲区里的头部空间；
    3、读取网络设备硬件上接收到的数据；
    4、使用memcpy()将数据复制到新的sk_buff里的data成员指向的地址处,可以使用skb_put()来动态扩大sk_buff结构体里中的数据区；
    5、使用eth_type_trans()来获取上层协议,将返回值赋给sk_buff的protocol成员里；
    6、然后更新统计信息，最后使用netif_rx( )来将sk_fuffer传递给上层协议中。

*/

/*
NAPI ：
    中断（用来唤醒数据接收服务程序）+ 轮询（在接受服务程序中采用POLL的方法来轮询处理数据）
    数据接收流程为：“接收中断来临->关闭接收中断->以轮询方式接收所有数据包直到收空->开启接收中断->接收中断来临……”
    NAPI 的优势在于，当数据包到达时，NAPI 会关闭中断，然后开始接收数据包，直到接收缓冲区满或者没有更多的数据包可接收。
    然后，NAPI 会重新打开中断，并让内核继续处理其他任务。这样，NAPI 可以减少中断处理的次数，从而提高系统的性能。
*/



/*
 * 参考 drivers\net\cs89x0.c
 */

static struct net_device *vnet_dev;


/*虚拟网卡的 接收函数*/
static void emulator_rx_packet(struct sk_buff *skb, struct net_device *dev)
{
	unsigned char *type;
	struct iphdr *ih;
	__be32 *saddr, *daddr, tmp;
	unsigned char	tmp_dev_addr[ETH_ALEN];
	struct ethhdr *ethhdr;
	
	struct sk_buff *rx_skb;
	
	/* 1.对调ethhdr结构体的"源/目的"的mac地址 */
	ethhdr = (struct ethhdr *)skb->data;
	memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
	memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
	memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);

	/* 2.对调iphdr结构体的"源/目的"的ip地址 */    
	ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
	saddr = &ih->saddr;
	daddr = &ih->daddr;

	tmp = *saddr;
	*saddr = *daddr;
	*daddr = tmp;
	
	/* 3.使用ip_fast_csum()来重新获取iphdr结构体的校验码*/
	ih->check = 0;		   /* and rebuild the checksum (ip needs it) */
	ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
	
	/* 4.设置数据类型*/
	type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);
	*type = 0; /*原来0x8表示发送ping包，现在0表示接收ping包 */
	
	/* 5.构造一个新的sk_buff */
	rx_skb = dev_alloc_skb(skb->len + 2);
	
	/* 6.使用skb_reserve腾出2字节头部空间*/
	skb_reserve(rx_skb, 2); /* align IP on 16B boundary */	
	
	/* 7.将之前修改好的sk_buff->data复制到新的sk_buff里 */
	memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);	//用skb_put()扩大sk_buff的数据区，避免溢出

	/* 8.设置新sk_buff的其它成员*/
	rx_skb->dev = dev;
	rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
	
	/* 9.使用eth_type_trans()来获取上层协议 */
	rx_skb->protocol = eth_type_trans(rx_skb, dev);
	
	/* 10.更新接收统计信息,并向上层传递sk_fuffer收包 */
	dev->stats.rx_packets++;
	dev->stats.rx_bytes += skb->len;
    dev->last_rx = jiffies;		//收包时间戳

	// 提交sk_buff
	netif_rx(rx_skb);
}
/*虚拟网卡的发送函数 */
static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)
{
	static int cnt = 0;
	printk("virt_net_send_packet cnt = %d\n", ++cnt);

	/* 1.停止该网卡的队列，阻止上层向驱动层继续发送数据包 */
	netif_stop_queue(dev); 
	
    /* 2.真实驱动要把skb的数据写入网卡 ，但在此先通过emulator_rx_packet模拟 */
	emulator_rx_packet(skb, dev);	/* 构造一个假的sk_buff,上报 */

	/* 3.释放发送的sk_buff缓存区*/
	dev_kfree_skb (skb);
	
	/* 4.更新统计信息 */
	dev->stats.tx_packets++;
	dev->stats.tx_bytes += skb->len;
    dev->trans_start = jiffies;	//发送时间戳
	
	/* 5.数据全部发送出去后,唤醒网卡的队列 （真实网卡应在中断函数里唤醒）*/
	netif_wake_queue(dev); 
	
	return 0;
}

/*  绑定数据发送的函数 */
static const struct net_device_ops vnetdev_ops = {
	.ndo_start_xmit		= virt_net_send_packet,
};

static int virt_net_init(void)
{
	/* 1. 分配一个net_device结构体 */
	vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);;  /* alloc_ether_dev */

	/* 2. 设置 */
	//vnet_dev->hard_start_xmit = virt_net_send_packet;
	vnet_dev->netdev_ops	= &vnetdev_ops;

	/* 设置MAC地址 */
    vnet_dev->dev_addr[0] = 0x08;
    vnet_dev->dev_addr[1] = 0x89;
    vnet_dev->dev_addr[2] = 0x66;
    vnet_dev->dev_addr[3] = 0x77;
    vnet_dev->dev_addr[4] = 0x88;
    vnet_dev->dev_addr[5] = 0x99;

    /* 设置下面两项才能ping通 */
	vnet_dev->flags           |= IFF_NOARP;
	vnet_dev->features        |= NETIF_F_IP_CSUM;

	/* 3. 注册 */
	//register_netdevice(vnet_dev);		//编译会出错！
	register_netdev(vnet_dev);
	
	return 0;
}

static void virt_net_exit(void)
{
	unregister_netdev(vnet_dev);
	free_netdev(vnet_dev);
}

module_init(virt_net_init);
module_exit(virt_net_exit);

MODULE_AUTHOR("xxx");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("a virtual network device");



/*
CS8900 网卡简介
    寄存器                                      简介
LINECTL(0112H)	            决定 CS8900 的基本配置和物理接口，可选择使用 10BASE-T 接口、AUI 接口或者自动选择。
RXCTL(0104H)	            控制 CS8900 接收特定数据包，控制是否接收多播、广播和单播包。
RXCFG(0102H)	            RXCFG 控制 CS8900 接收到特定数据包后引发接收中断，并控制是否使用接收 DMA 和 CRC 校验。
BUSCT(0116H)	            BUSCT 可控制芯片的工作模式、DMA 方式、是否使能外部中断引脚。
BUSST(0138H)	            标志网络设备的发送状态，如设备是否准备好发送。
ISQ(0120H)	                网卡芯片的中断状态寄存器

在 I/O 模式下，CS8900 发送数据包的步骤如下：
    （1）向控制寄存器 TXCMD 寄存器写入发送命令write_reg(TXCMD, send_cmd);。
    （2）将发送数据长度写入 TXLENG 寄存器write_reg(TXLENG, send_len)。
    （3）读取 PacketPage 空间内的 BUSST 寄存器，确定其第 8 位被设置为 Rdy4TxNOW，即设备处于准备发送状态reg(BusST)&0x100。
    （4）将要发送的数据循环写入 PORT0 寄存器write_reg(PORT0, data)。
    （5）将数据组织为以太网帧并添加填充位和 CRC 校验信息，然后将数据转化为比特流传送到网络媒介。

在 I/O 模式下，CS8900 接收数据包的方法如下：
    （1）接收到网络适配器产生的中断，查询相对于 I/O 基地址偏移 0008H 中断状态 队列端口，判断中断类型为接收中断。
    （2）读 PORT0 寄存器依次获得接收状态 rxStatus、接收数据长度 rxLength。
    （3）循环继续对 PORT0 寄存器读取 rxLength 次，获得整个数据包。
    （4）驱动程序进行数据包处理并传递给上层。


网卡移植的步骤：
到一块新的网卡，一般厂家会有自带的驱动程序给你，你所要做的就是以下几个事情：

    根据网卡与开发板的连接方式确定网卡的内存映射地址iobase，也即确定网卡的片选信号所连接的CPU内存的哪一个bank（nGCS？），然后根据网卡内存的大小，在网卡驱动的初始化函数中调用ioremap()进行地址重映射；
    根据网卡与开发板的硬件连接图确定中断号，并在初始化函数中利于request_irq()函数，向内核申请中断（确定中断触发方式、中断处理函数等）；
    根据网卡datasheet查看网卡的读写时序和位宽参数，设置开发板相应的内存控制寄存器BWSCON和BANKCON*。
    将它拷贝到内核源代码的相关目录并修改该目录下的Makefile文件以添加修改后的网卡驱动目标文件。假设我们已经改好的网卡驱动程序为：dm9dev9000c.c，编译也没有错误。
*/










//填充 CS8900 的私有信息结构体
static struct net_device dev_cs89x0 = 
{ 
	"", 
 	0, 0, 0, 0, 
 	0, 0, 
 	0, 0, 0, NULL, NULL 
};

struct net_local 
{ 
	struct net_device_stats stats; /* 网络设备状态结构体 */ 
	int chip_type; /* 区分芯片类型：CS89x0 */ 
	char chip_revision; /* 芯片版本字母，如"A" */ 
	int send_cmd; /* 发送命令: TX_NOW, TX_AFTER_381 或 TX_AFTER_ALL */ 
	... 
    spinlock_t lock; /* 并发控制自旋锁 */ 
}; 




static unsigned int netcard_portlist[] __initdata = 
{ 
    vCS8900_BASE + 0x300,	//假设硬件平台中网卡的基地址为 vCS8900_BASE + 0x300
    0
}; 

/*
 *上述 cs89x0_probe1()函数的流程如下。
 *（1）第 8～20 行分配设备的私有信息结构体内存并初始化，若分配失败，则直接跳入第 78 行的代码返回。
 *（2）第 24～26 行从寄存器中读取芯片的具体类型。
 *（3）第 27～32 行判断芯片类型，若不是 CS8900 则直接跳入第 77 行的代码，释放私有信息结构体并返回。
 *（4）当芯片类型为 CS8900 时，第 34～69 行完成 net_device 设备结构体的初始化，赋值其属性和函数指针。
 */

static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
{ 
	struct net_local *lp; 
	unsigned rev_type = 0; 
	int ret; 
 
 	/* 分配设备的私有信息结构体内存并初始化 */ 
 	if (dev->priv == NULL) 
	{ 
 		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); 
		if (dev->priv == 0) 
		{ 
			ret = - ENOMEM; 
			goto before_kmalloc; 
		} 
	lp = (struct net_local*)dev->priv; 
	memset(lp, 0, sizeof(*lp)); 
	spin_lock_init(&lp->lock); 
	} 
	lp = (struct net_local*)dev->priv; 

	dev->base_addr = ioaddr; 
	/* 读取芯片类型 */ 
	rev_type = readreg(dev, PRODUCT_ID_ADD); 
	lp->chip_type = rev_type &~REVISON_BITS;
 	lp->chip_revision = ((rev_type &REVISON_BITS) >> 8) + 'A';30 
	if (lp->chip_type != CS8900) 
	{ 
		printk(_ _FILE_ _ ": wrong device driver!\n"); 
		ret = - ENODEV; 
		goto after_kmalloc;
	} 
	/* 根据芯片类型和版本确定正确的发送命令 */ 
	lp->send_cmd = TX_AFTER_ALL; 
	if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') 
		lp->send_cmd = TX_NOW; 

	reset_chip(dev); 

	lp->adapter_cnf = A_CNF_10B_T | A_CNF_MEDIA_10B_T; 
	lp->auto_neg_cnf = EE_AUTO_NEG_ENABLE;
	printk(KERN_INFO "cs89x0 media %s%s", (lp->adapter_cnf &A_CNF_10B_T) ? "RJ-45": "", (lp->adapter_cnf &A_CNF_AUI) ? "AUI" : ""); 

 	/* 设置 CS8900 的 MAC 地址 */ 
	dev->dev_addr[0] = 0x00; 
	dev->dev_addr[1] = 0x00; 
	dev->dev_addr[2] = 0xc0; 
	dev->dev_addr[3] = 0xff; 
	dev->dev_addr[4] = 0xee; 
	dev->dev_addr[5] = 0x08; 
 	set_mac_address(dev, dev->dev_addr); 
 
	/* 设置设备中断号 */ 
	dev->irq = IRQ_LAN; 
	printk(", IRQ %d", dev->irq); 
 
	/* 填充设备结构体的成员函数指针 */ 
	dev->open = net_open; 
	dev->stop = net_close; 
	dev->tx_timeout = net_timeout; 
	dev->watchdog_timeo = 3 * HZ; 
	dev->hard_start_xmit = net_send_packet; 
	dev->get_stats = net_get_stats; 
	dev->set_multicast_list = set_multicast_list; 
	dev->set_mac_address = set_mac_address; 
 
	/* 填充以太网公用数据和函数指针 */ 
	ether_setup(dev); 

	printk("\n"); 
	DPRINTK(1, "cs89x0_probe1() successful\n"); 
	return 0;
  	after_kmalloc: kfree(dev->priv); 
	before_kmalloc: return ret; 
} 



//填充设备初始化模板，初始化 net_device 结构体，将其注册入内核
int __init cs89x0_probe(struct net_device *dev) 
{ 
	int i; 
 
	SET_MODULE_OWNER(dev); 
	DPRINTK(1, "cs89x0:cs89x0_probe(0x%x)\n", base_addr); 

	BWSCON = (BWSCON & ~(BWSCON_ST3 | BWSCON_WS3 | BWSCON_DW3)) | 
				(BWSCON_ST3 | BWSCON_WS3 | BWSCON_DW(3, BWSCON_DW_16)); 
	BANKCON3= BANKCON_Tacs0 | BANKCON_Tcos4 | BANKCON_Tacc14 | 
				BANKCON_Toch1 | BANKCON_Tcah4 | BANKCON_Tacp6 | BANKCON_PMC1; 
 
	set_external_irq(IRQ_CS8900, EXT_RISING_EDGE, GPIO_PULLUP_DIS); 

 	for (i = 0; netcard_portlist[i]; i++) 
    { 
 		if (cs89x0_probe1(dev, netcard_portlist[i]) == 0) //验证网卡的存在，并获取 CS8900所使用的硬件资源
			return 0; 
	}
	printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected." 
       "Be sure to disable PnP with SETUP\n"); 
	return -ENODEV; 
}


static int __init init_cs8900a_s3c2410(void) 
{ 
	struct net_local *lp;
	int ret = 0; 
 
	dev_cs89x0.irq = irq; 
	dev_cs89x0.base_addr = io; 
	dev_cs89x0.init = cs89x0_probe; //在使用 register_netdev()函数注net_device 设备结构体时，cs89x0_probe()函数会被自动调用以完成 net_device 结构体的初始化。
	dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); 
	if (dev_cs89x0.priv == 0) 
	{ 
		printk(KERN_ERR "cs89x0.c: Out of memory.\n"); 
		return - ENOMEM; 
	} 
	memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); 
	lp = (struct net_local*)dev_cs89x0.priv; 
    
 	//为 CS8900 网卡申请了 NETCARD_IO_EXTENT大小的I/O 地址区域
	request_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT, "cs8900a");
    spin_lock_init(&lp->lock); 
 
	/* 设置物理接口的正确类型*/ 
	if (!strcmp(media, "rj45")) 
	    lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; 
	else if (!strcmp(media, "aui")) 
		lp->adapter_cnf = A_CNF_MEDIA_AUI | A_CNF_AUI; 
	else if (!strcmp(media, "bnc")) 
		lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2; 
	else 
		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; 
 
	if (duplex == - 1) 
		lp->auto_neg_cnf = AUTO_NEG_ENABLE; 
 
	if (io == 0) 
	{ 
		printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n"); 
		printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n"); 
		ret = - EPERM; 
		goto out; 
	} 
 	//net_device 设备结构体的注册
	if (register_netdev(&dev_cs89x0) != 0) 
	{ 
		printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io); 
		ret = - ENXIO; 
		goto out; 
	} 
out: if (ret) 
		kfree(dev_cs89x0.priv); 
	return ret; 
} 


static void _ _exit cleanup_cs8900a_s3c2410(void) 
{ 
	if (dev_cs89x0.priv != NULL) 
	{ 
		/* 释放私有信息结构体 */ 
		unregister_netdev(&dev_cs89x0); 
		outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); 
		kfree(dev_cs89x0.priv); 
		dev_cs89x0.priv = NULL; 
		/* 释放 CS8900 申请的 I/O 地址区域 */ 
        release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT); 
	} 
} 



// 填充设备发送数据包函数模板
static int net_send_packet(struct sk_buff *skb, struct net_device  *dev)
{
    struct net_local *lp = (struct net_local*)dev->priv; 
 
	writereg(dev, PP_BusCTL, 0x0); 
	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); 
 
	spin_lock_irq(&lp->lock);/* 使用自旋锁阻止多个数据包被同时写入硬件*/ 
	netif_stop_queue(dev); 
 
	/* 初始化硬件发送序列 */ 
	writeword(dev, TX_CMD_PORT, lp->send_cmd); 
	writeword(dev, TX_LEN_PORT, skb->len); 
 
	/* 检测硬件是否处于发送 READY 状态 */ 
	if ((readreg(dev, PP_BusST) &READY_FOR_TX_NOW) == 0) 
	{ 
		spin_unlock_irq(&lp->lock); 
		DPRINTK(1, "cs89x0: Tx buffer not free!\n"); 
		return 1; 
	} 
 
	writeblock(dev, skb->data, skb->len);	/* 将数据写入硬件 */ 
 
	spin_unlock_irq(&lp->lock); 	/* 解锁自旋锁 */ 
	dev->trans_start = jiffies; 	/* 记录发送开始的时间戳 */ 
	dev_kfree_skb(skb); 			/* 释放 sk_buff 和数据缓冲区 */ 
 
	return 0; 
}

static void net_timeout(struct net_device *dev)
{ 
	DPRINTK(1, "%s: transmit timed out, %s?\n", dev->name,
		tx_done(dev) ? "IRQ conflict ?" : "network cable problem"); 
 
	net_close(dev); //停止网卡
	writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); //网卡硬复位
	net_open(dev); //再次启动网卡
} 




//填充设备驱动程序的中断处理程序 xxx_interrupt()和具体的数据包接收函数 xxx_rx()

irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ 
	struct net_device *dev = dev_id; 
	struct net_local *lp; 
	int ioaddr, status; 
 
	ioaddr = dev->base_addr; 
	lp = (struct net_local*)dev->priv; 
 
	/* 读取中断事件类型 */ 
	while ((status = readword(dev, ISQ_PORT))) 
	{ 
		DPRINTK(4, "%s: event=%04x\n", dev->name, status); 
		switch (status &ISQ_EVENT_MASK) 
		{ 
			case ISQ_RECEIVER_EVENT: 
				/* 获得数据包 */ 
				net_rx(dev); 
				break; 
			... /* 其他类型中断 */ 
		} 
	} 
} 


static void net_rx(struct net_device *dev)
{
    struct net_local *lp = (struct net_local*)dev->priv; 
	struct sk_buff *skb; 
	int status, length; 
 
	int ioaddr = dev->base_addr; 
 
	status = inw(ioaddr + RX_FRAME_PORT); 
	if ((status &RX_OK) == 0) 
	{ 
		count_rx_errors(status, lp); 
		return ; 
	} 
 
	length = inw(ioaddr + RX_FRAME_PORT);/* 读取接收数据包的长度 */ 
 
	/* 分配新的套接字缓冲区和数据缓冲区 */ 
	skb = dev_alloc_skb(length + 2); 
	if (skb == NULL) 
	{ 
		lp->stats.rx_dropped++; /* 分配失败，统计被丢弃的包数 */ 
		return ; 
	} 
	skb_reserve(skb, 2); 
	skb->len = length; 
	skb->dev = dev;
	readblock(dev, skb->data, skb->len); /* 从硬件中读取数据包放入数据缓冲区 */
    skb->protocol = eth_type_trans(skb, dev);/* 解析收到数据包的网络层协议类型 */ 
 
	netif_rx(skb); /* 传递给上层协议 */ 
 
	dev->last_rx = jiffies; /* 记录最后收到数据包的时间戳 */ 
	/* 统计接收数据包数和接收字节数 */ 
	lp->stats.rx_packets++; 
	lp->stats.rx_bytes += length; 
} 




